package tree

import "fmt"

/*
go语言仅支持封装, 不支持继承和多态
所以go语言没有class, 只有struct

不论地址还是结构体本身, 在go中一律使用 . 来访问(c中需要使用 -> 访问指针)

值接收者 vs 指针接收者
值接收者 是go语言特有(java非基础类型默认指针接收)
接收者可以接收 值/指针

封装:
名字一般使用camelCase (驼峰命名)
首字母大写: public
首字母小写: private

包:
每个目录一个包
main包,包含了可执行入口
为结构定义的方法必须放在同一个包内, 但可以是不同的文件
*/

type Node struct {
	Value       int
	Left, Right *Node
}

//go没有构造函数, 因为提供了很多初始化方法
//如需要特定的初始化,可以自定义工厂函数
func CreateNode(value int) *Node {
	//工厂函数一般返回局部变量的地址
	//c语言中这么操作是会报错的(局部变量是在栈上分配的,函数执行完成则弹出销毁,之后会无法获取到变量,必须要在堆上分配)
	//java需要使用new, new的对象是分配在堆上的
	return &Node{Value: value}
}

// node Node 类似其他语言的 this, go中称为接收者(名称可以自定义, go中没有this关键字)
// 这种方式方便了链式 . 调用
func (node Node) Print() {
	fmt.Print(node.Value, " ")
}

//等价 (node Node) Print() 方法
func Print(node Node) {
	fmt.Print(node.Value, " ")
}

//需要加 * 用于引用传递, 否则还是值传递
func (node *Node) SetValue(value int) {
	if node == nil {
		fmt.Println("Setting Value to nil node. Ignored.")
		return
	}
	node.Value = value
}

func (node *Node) Traverse() {
	if node == nil {
		return
	}
	node.Left.Traverse()
	//中序遍历(利用递归序)
	node.Print()
	node.Right.Traverse()
}

func main() {
	DefinedAndInitUdfType()
}

func DefinedAndInitUdfType() {
	var root Node
	//初始化一个值
	root = Node{Value: 3}
	//默认值初始化
	root.Left = &Node{}
	root.Left.Right = CreateNode(2)
	//不指定字段初始化需要给所有字段赋值
	root.Right = &Node{5, nil, nil}
	//注意: 指针类型(*)在go中也可以用 . 来获取其值
	root.Right.Left = new(Node)
	/*
			3
		0		5
		  2   0
	*/
	fmt.Println("root=", root, " root.Left=", root.Left, " root.Right", root.Right)

	root.Print()
	Print(root)
	fmt.Println()

	//这里需要注意值传递还是引用传递
	root.Right.Left.SetValue(4)
	root.Right.Left.Print()
	fmt.Println()

	var nilRoot *Node
	nilRoot.SetValue(200)
	nilRoot = CreateNode(100)
	nilRoot.SetValue(300)
	nilRoot.Print()
	fmt.Println()

	root.Traverse()
	fmt.Println()
}
